package com.unittec.zk.provider.service;

import com.alibaba.fastjson.JSON;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.unittec.zk.provider.common.WebUtils;
import com.unittec.zk.provider.scope.ThreadLocalScope;
import com.unittec.zk.provider.ApplicationContextProvider;
import com.unittec.zk.provider.log.Log;
import com.unittec.zk.sdk.root.common.FieldConstants;
import com.unittec.zk.sdk.root.domain.GatewayRequest;
import com.unittec.zk.sdk.root.domain.Result;
import com.unittec.zk.sdk.root.enums.BizCode;
import com.unittec.zk.sdk.root.internal.exception.BusinessException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

@Service
public class HystrixRestTemplateService {
    private Log log;
    @Autowired
    private RestTemplate restTemplate;

    public <T, M> Result<T> exchangeError(String url, GatewayRequest<M> request, ThreadLocalScope.AuthData authData,
                                          ParameterizedTypeReference<Result<T>> result, Throwable throwable) {
        String logmsg = String.format("exchange url=[%s] requestId=[%s] appId=[%s] tenantId=[%s]", url,
                authData.getRequestId(), authData.getAppId(), authData.getTenantId());

        if (null == log) {
            synchronized (this) {
                if (null == log) {
                    log = ApplicationContextProvider.getBean(Log.class);
                }
            }
        }
        log.sysErrLog("exchangeError", logmsg + "--" + throwable.toString(), throwable);
        return Result.error(request, BizCode.SERVICE_EXCEPTION.getCode(),
                "接口" + org.apache.commons.lang.StringUtils.substringAfterLast(url, "/")
                        + BizCode.SERVICE_EXCEPTION.getMessage());
    }

    @HystrixCommand(fallbackMethod = "exchangeError")
    public <T, M> Result<T> exchange(String url, GatewayRequest<M> request, ThreadLocalScope.AuthData authData,
                                     ParameterizedTypeReference<Result<T>> result) {
        Result<T> t = null;
        try {
            String token = authData.getToken();
            if (null != token && token.contains(FieldConstants.REQ_BEARER)) {
                token = token.substring(7);
            }
            MultiValueMap<String, String> values = new LinkedMultiValueMap<String, String>();
            if (StringUtils.isNotBlank(authData.getTenantId())) {
                values.add(FieldConstants.TENANT_ID, authData.getTenantId());
                values.add(FieldConstants.APP_ID, authData.getAppId());
                values.add(FieldConstants.LOGIN_USER, authData.getUser());
                values.add(FieldConstants.REQUEST_ID, authData.getRequestId());
                values.add(FieldConstants.APP_CODE, authData.getAppCode());
            } else {
                values.add(FieldConstants.REQUEST_ID, authData.getRequestId());
                values.add(FieldConstants.APP_ID, authData.getAppId());
                values.add(FieldConstants.APP_CODE, authData.getAppCode());
                values.add(FieldConstants.LOGIN_USER, authData.getUser());
            }
            if (StringUtils.isBlank(request.getAppId())) {
                request.setAppId(authData.getAppId());
            }
            if (StringUtils.isBlank(request.getRequestId())) {
                request.setRequestId(authData.getRequestId());
            }
            request.setToken(authData.getToken());
            HttpHeaders headers = WebUtils.buildHttpHeaders(token);
            headers.addAll(values);
            String logmsg =
                    String.format("exchange url=[%s] method=[%s] requestId=[%s] appId=[%s] tenantId=[%s]  param=[%s]", url,
                            request.getMethod(), request.getRequestId(), request.getAppId(), authData.getTenantId(),
                            request.getContent() != null ? JSON.toJSONString(request.getContent()) : "");
            if (null == log) {
                synchronized (this) {
                    if (null == log) {
                        log = ApplicationContextProvider.getBean(Log.class);
                    }
                }
            }
            log.sysInfoLog("hystrixRestTemplateService exchange begin ", logmsg);
            if (restTemplate == null) {
                synchronized (this) {
                    if (null == restTemplate) {
                        restTemplate = ApplicationContextProvider.getBean(RestTemplate.class);
                    }
                }
            }
            t = restTemplate.exchange(url, HttpMethod.POST,
                    new org.springframework.http.HttpEntity<GatewayRequest<M>>(request, headers), result).getBody();
            if (t != null) {
                log.sysInfoLog("hystrixRestTemplateService exchange end ", "result:{}", JSON.toJSONString(t));
                return t;
            }
            log.sysInfoLog("hystrixRestTemplateService  exchange end ", "result is null  ");
            throw new BusinessException("restTemplate 请求报错:result is null");
        } catch (Exception e) {
            throw new BusinessException("restTemplate 请求报错:" + e.getMessage());
        }
    }

    /**
     * 系统自己发起的请求 的错误消息
     *
     * @param sysRequestSourceId
     * @param url
     * @param request
     * @param authData
     * @param result
     * @param throwable
     * @param <T>
     * @param <M>
     * @return
     */
    public <T, M> Result<T> exchangeError(String sysRequestSourceId, String url, GatewayRequest<M> request, ThreadLocalScope.AuthData authData,
                                          ParameterizedTypeReference<Result<T>> result, Throwable throwable) {
        String logmsg = String.format("exchange url=[%s] requestId=[%s] appId=[%s] tenantId=[%s]", url,
                authData.getRequestId(), authData.getAppId(), authData.getTenantId());
        return Result.error(request, BizCode.SERVICE_EXCEPTION.getCode(),
                "接口" + org.apache.commons.lang.StringUtils.substringAfterLast(url, "/")
                        + BizCode.SERVICE_EXCEPTION.getMessage());
    }

    /**
     * 系统自己发起的请求
     *
     * @param sysRequestSourceId
     * @param url
     * @param request
     * @param authData
     * @param result
     * @param <T>
     * @param <M>
     * @return
     */
    @HystrixCommand(fallbackMethod = "exchangeError")
    public <T, M> Result<T> exchange(String sysRequestSourceId, String url, GatewayRequest<M> request, ThreadLocalScope.AuthData authData,
                                     ParameterizedTypeReference<Result<T>> result) {
        Result<T> t = null;
        try {
            if (authData == null) {
                authData = ThreadLocalScope.getAuthData();
            }
            String token = authData.getToken();
            if (null != token && token.contains(FieldConstants.REQ_BEARER)) {
                token = token.substring(7);
            }
            MultiValueMap<String, String> values = new LinkedMultiValueMap<>();
            values.add(FieldConstants.TENANT_ID, authData.getTenantId());
            values.add(FieldConstants.APP_ID, authData.getAppId() == null ? FieldConstants.SYS_APP_ID : authData.getAppId());
            values.add(FieldConstants.LOGIN_USER, authData.getUser() == null ? "-1" : authData.getUser() + "");
            values.add(FieldConstants.REQUEST_ID, authData.getRequestId());
            values.add(FieldConstants.APP_CODE, authData.getAppCode());
            if (StringUtils.isBlank(request.getAppId())) {
                request.setAppId(authData.getAppId());
            }
            if (StringUtils.isBlank(request.getRequestId())) {
                request.setRequestId(authData.getRequestId());
            }
            //系统请求标识，有次标识 请求不会验证token
            values.add(FieldConstants.SYS_REQUEST_SOURCE, sysRequestSourceId);
            request.setToken(authData.getToken());
            HttpHeaders headers = WebUtils.buildHttpHeaders(token);
            headers.addAll(values);
            String logmsg =
                    String.format("exchange url=[%s] method=[%s] requestId=[%s] appId=[%s] tenantId=[%s]  param=[%s]", url,
                            request.getMethod(), request.getRequestId(), request.getAppId(), authData.getTenantId(),
                            request.getContent() != null ? JSON.toJSONString(request.getContent()) : "");
            if (null == log) {
                synchronized (this) {
                    if (null == log) {
                        log = ApplicationContextProvider.getBean(Log.class);
                    }
                }
            }
            log.sysInfoLog("hystrixRestTemplateService exchange begin ", logmsg);
            if (restTemplate == null) {
                synchronized (this) {
                    if (null == restTemplate) {
                        restTemplate = ApplicationContextProvider.getBean(RestTemplate.class);
                    }
                }
            }
            t = restTemplate.exchange(url, HttpMethod.POST,
                    new org.springframework.http.HttpEntity<>(request, headers), result).getBody();
            if (t != null) {
                log.sysInfoLog("hystrixRestTemplateService exchange end ", "result:{}", JSON.toJSONString(t));
                return t;
            }
            log.sysInfoLog("hystrixRestTemplateService  exchange end ", "result is null  ");
            throw new BusinessException("restTemplate 请求报错:result is null");
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException("restTemplate 请求报错:" + e.getMessage());
        }
    }
}
